//
//  UIButton+APMTimer.m
//  FXManager
//
//  Created by lcj on 2020/12/8.
//  Copyright © 2020 华旅电子. All rights reserved.
//

#import "UIButton+APMTimer.h"
#import <objc/runtime.h>

static char APMButtonTimerMarkKey;
static char APMButtonTimerGCDTimerKey;
static char APMButtonTimerRunningKey;
static char APMButtonTimerSecondsKey;
static char APMButtonTimerArchiverDicKey;

static NSString * _apm_button_timer_document_path(){
    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}

@interface UIButton (_APMTimer)
@property (readwrite, nonatomic, copy, setter = apm_setTimerMark:) NSString * apm_timer_mark;
@property (readwrite, nonatomic, strong, setter = apm_setGCDTimer:) dispatch_source_t apm_timer_gcd_timer;
@property (readwrite, nonatomic, assign, setter = apm_setTimerRunning:) BOOL apm_timer_running;
@property (readwrite, nonatomic, assign, setter = apm_setTimerSeconds:) NSInteger apm_timer_seconds;
@property (readwrite, nonatomic, strong, setter = apm_setTimerDictionary:) NSMutableDictionary * apm_timer_dictionary;
@end

@implementation UIButton (_APMTimer)

- (NSString *)apm_timer_mark {
    return (NSString *)objc_getAssociatedObject(self, &APMButtonTimerMarkKey);
}

- (void)apm_setTimerMark:(NSString *)timerMark {
    objc_setAssociatedObject(self, &APMButtonTimerMarkKey, timerMark, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (dispatch_source_t)apm_timer_gcd_timer {
    return (dispatch_source_t)objc_getAssociatedObject(self, &APMButtonTimerGCDTimerKey);
}

- (void)apm_setGCDTimer:(dispatch_source_t)gcdTimer {
    objc_setAssociatedObject(self, &APMButtonTimerGCDTimerKey, gcdTimer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (BOOL)apm_timer_running {
    return [(NSNumber *)objc_getAssociatedObject(self, &APMButtonTimerRunningKey) boolValue];
}

- (void)apm_setTimerRunning:(BOOL)timerRunning {
    objc_setAssociatedObject(self, &APMButtonTimerRunningKey, [NSNumber numberWithBool:timerRunning], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSInteger)apm_timer_seconds {
    return [(NSNumber *)objc_getAssociatedObject(self, &APMButtonTimerSecondsKey) integerValue];
}

- (void)apm_setTimerSeconds:(NSInteger)timerSeconds {
    objc_setAssociatedObject(self, &APMButtonTimerSecondsKey, [NSNumber numberWithInteger:timerSeconds], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSMutableDictionary *)apm_timer_dictionary {
    NSMutableDictionary * dictionary = (NSMutableDictionary *)objc_getAssociatedObject(self, &APMButtonTimerArchiverDicKey);
    if (dictionary == nil) {
        dictionary = [self _apm_unArchiveDictionary];
        if (dictionary == nil) {
            dictionary = [NSMutableDictionary dictionary];
        }
        self.apm_timer_dictionary = dictionary;
    }
    return dictionary;
}

- (void)apm_setTimerDictionary:(NSMutableDictionary *)timerDictionary {
    objc_setAssociatedObject(self, &APMButtonTimerArchiverDicKey, timerDictionary, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)_apm_timer_mark_file_path {
    NSString * filePath = [_apm_button_timer_document_path() stringByAppendingPathComponent:@"APMTimerMark.plist"];
    return filePath;
}

- (void)_apm_archiveDictionary {
    if (@available(iOS 12.0, *)) {
           [NSKeyedArchiver archivedDataWithRootObject:self.apm_timer_dictionary requiringSecureCoding:YES error:nil];
       } else {
           [NSKeyedArchiver archiveRootObject:self.apm_timer_dictionary toFile:[self _apm_timer_mark_file_path]];
       }
}

- (NSMutableDictionary *)_apm_unArchiveDictionary {
    NSString * filePath = [self _apm_timer_mark_file_path];
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]){
        return (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
    }
    return nil;
}

@end

@interface NSDate (_APMTimer)

@end

@implementation NSDate (_APMTimer)
+ (long)_apm_button_timer_currentTimestamp {
    NSDate * date = [NSDate dateWithTimeIntervalSinceNow:0];
    long timestamp = (long)[date timeIntervalSince1970];
    return timestamp;
}
@end

@implementation UIButton (APMTimer)

- (long)_apm_timer_get_start_timestamp_with_mark:(NSString *)mark {
    return [[self.apm_timer_dictionary objectForKey:[mark stringByAppendingString:@"_start"]] longValue];
}

- (void)_apm_timer_save_start_timestamp_with_timestamp:(long)timestamp mark:(NSString *)mark {
    [self.apm_timer_dictionary setObject:[NSNumber numberWithLong:timestamp] forKey:[mark stringByAppendingString:@"_start"]];
    [self _apm_archiveDictionary];
}

- (NSInteger)_apm_timer_get_seconds_with_mark:(NSString *)mark {
    return [[self.apm_timer_dictionary objectForKey:[mark stringByAppendingString:@"_seconds"]] integerValue];
}

- (void)_apm_timer_save_seconds_with_seconds:(NSInteger)seconds mark:(NSString *)mark {
    [self.apm_timer_dictionary setObject:[NSNumber numberWithInteger:seconds] forKey:[mark stringByAppendingString:@"_seconds"]];
    [self _apm_archiveDictionary];
}

- (void)_apm_timer_remove_all_value_for_mark:(NSString *)mark {
    NSString * _startKey = [mark stringByAppendingString:@"_start"];
    NSString * _secondsKey = [mark stringByAppendingString:@"_seconds"];
    [self.apm_timer_dictionary removeObjectForKey:_startKey];
    [self.apm_timer_dictionary removeObjectForKey:_secondsKey];
    [self _apm_archiveDictionary];
}

- (void)_apm_timer_start_timer {
    self.userInteractionEnabled = NO;
    self.selected = YES;
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    self.apm_timer_gcd_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_timer(self.apm_timer_gcd_timer, dispatch_walltime(DISPATCH_TIME_NOW,0.0*NSEC_PER_SEC), 1.0 * NSEC_PER_SEC, 0.0 * NSEC_PER_SEC);
    __weak typeof(self) weakSelf = self;
    dispatch_source_set_event_handler(self.apm_timer_gcd_timer, ^{
        weakSelf.apm_timer_seconds--;
        dispatch_async(dispatch_get_main_queue(), ^{
            if (weakSelf.apm_timer_seconds > 0 ) {
                // 计时器停止
                [weakSelf setTitle:[NSString stringWithFormat:@"%ld",(long)weakSelf.apm_timer_seconds] forState:UIControlStateSelected];
            }else {
                [weakSelf _apm_timer_stop_timer];
            }
        });
    });
    dispatch_resume(self.apm_timer_gcd_timer);
    self.apm_timer_running = YES;
}


- (void)_apm_timer_stop_timer {
    if (self.apm_timer_gcd_timer && self.apm_timer_running) {
        self.userInteractionEnabled = YES;
        self.selected = NO;
        dispatch_source_cancel(self.apm_timer_gcd_timer);
        self.apm_timer_gcd_timer = nil;
        self.apm_timer_running = NO;
        [self _apm_timer_remove_all_value_for_mark:self.apm_timer_mark];
    }
}

- (void)apm_startTimerWithSeconds:(NSInteger)seconds mark:(NSString *)mark {
    NSInteger _seconds = [self _apm_timer_get_seconds_with_mark:mark];
    self.apm_timer_mark = mark;
    if (_seconds == 0) {
        // 新的开始
        self.apm_timer_seconds = seconds;
        [self _apm_timer_save_seconds_with_seconds:seconds mark:mark];
        long startTimestamp = [NSDate _apm_button_timer_currentTimestamp];
        [self _apm_timer_save_start_timestamp_with_timestamp:startTimestamp mark:mark];
        [self _apm_timer_start_timer];
    } else {
        long startTimestamp = [self _apm_timer_get_start_timestamp_with_mark:mark];
        long currentTimestamp = [NSDate _apm_button_timer_currentTimestamp];
        if ((startTimestamp + _seconds) <= currentTimestamp) {
            self.apm_timer_seconds = seconds;
            [self _apm_timer_save_seconds_with_seconds:seconds mark:mark];
            [self _apm_timer_save_start_timestamp_with_timestamp:currentTimestamp mark:mark];
            [self _apm_timer_start_timer];
        } else {
            //上一次的还未执行完
            _seconds = startTimestamp + _seconds - currentTimestamp;
            self.apm_timer_seconds = _seconds;
            [self _apm_timer_save_seconds_with_seconds:_seconds mark:mark];
            [self _apm_timer_save_start_timestamp_with_timestamp:currentTimestamp mark:mark];
            [self _apm_timer_start_timer];
        }
    }
}

- (void)apm_resumeTimerWithMark:(NSString *)mark {
    NSInteger _seconds = [self _apm_timer_get_seconds_with_mark:mark];
    self.apm_timer_mark = mark;
    if (_seconds > 0) {
        long startTimestamp = [self _apm_timer_get_start_timestamp_with_mark:mark];
        long currentTimestamp = [NSDate _apm_button_timer_currentTimestamp];
        if (currentTimestamp < (startTimestamp + _seconds)) {
            _seconds = startTimestamp + _seconds - currentTimestamp;
            self.apm_timer_seconds = _seconds;
            [self _apm_timer_save_seconds_with_seconds:_seconds mark:mark];
            [self _apm_timer_save_start_timestamp_with_timestamp:currentTimestamp mark:mark];
            [self _apm_timer_start_timer];
        }
    }
}

- (void)apm_stopTimer {
    [self _apm_timer_stop_timer];
}
@end
